package top.fullj.bean;

import com.google.common.base.Preconditions;
import top.fullj.func.Tuple;

import java.util.Collection;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;

/**
 * @author bruce.wu
 * @since 2021/6/15 14:31
 */
@SuppressWarnings("WeakerAccess")
public abstract class PrintChar {

    private static final String PADDING = "                                            ";

    public static boolean isChinese(char ch) {
        Character.UnicodeBlock ub = Character.UnicodeBlock.of(ch);
        return ub == Character.UnicodeBlock.CJK_UNIFIED_IDEOGRAPHS
                || ub == Character.UnicodeBlock.CJK_COMPATIBILITY_IDEOGRAPHS
                || ub == Character.UnicodeBlock.CJK_UNIFIED_IDEOGRAPHS_EXTENSION_A
                || ub == Character.UnicodeBlock.CJK_UNIFIED_IDEOGRAPHS_EXTENSION_B
                || ub == Character.UnicodeBlock.CJK_SYMBOLS_AND_PUNCTUATION
                || ub == Character.UnicodeBlock.HALFWIDTH_AND_FULLWIDTH_FORMS
                || ub == Character.UnicodeBlock.GENERAL_PUNCTUATION;
    }

    /**
     * determine word wide when print
     *
     * @param ch test character
     * @return wide in printer paper
     */
    public static int wide(char ch) {
        return ch > 0x7FF ? 2 : 1;
    }

    public static int wide(String str) {
        if (str == null || str.isEmpty()) {
            return 0;
        }
        int len = str.length();
        int w = 0;
        for (int i = 0; i < len; i++) {
            w += wide(str.charAt(i));
        }
        return w;
    }

    public static String alignRight(String str, final int maxWide) {
        if (str == null || str.isEmpty()) {
            return "";
        }
        int lack = maxWide - wide(str);
        if (lack > 0) {
            return PADDING.substring(0, lack) + str;
        }
        return str;
    }

    public static String alignCenter(String str, final int maxWide) {
        if (str == null || str.isEmpty()) {
            return "";
        }
        int lack = (maxWide - wide(str)) / 2;
        if (lack > 0) {
            return PADDING.substring(0, lack) + str;
        }
        return str;
    }

    public static String justify(String left, String right, final int maxWide) {
        int lack = maxWide - wide(left) - wide(right);
        if (lack > 0) {
            return left + PADDING.substring(0, lack) + right;
        }
        return left + right;
    }

    public static boolean isOverflow(String str, final int maxWide) {
        return wide(str) > maxWide;
    }

    public static Collection<String> wrap(String str, final int maxWide) {
        Preconditions.checkNotNull(str);
        int w = wide(str);
        if (maxWide > w) {
            return Collections.singletonList(str);
        }
        int len = str.length();
        int start = 0;
        List<String> lines = new LinkedList<>();
        while (start < len) {
            Tuple<String, Integer> tuple = wrap(str, start, len, maxWide);
            lines.add(tuple.first);
            start = tuple.second;
        }
        return lines;
    }

    private static Tuple<String, Integer> wrap(String str, final int start, final int end, final int max) {
        Preconditions.checkArgument(start < end, "need start < end");
        int space = -1;
        int w = 0;
        for (int i = start; i < end; i++) {
            char ch = str.charAt(i);
            w += wide(ch);
            if (Character.isSpaceChar(ch)) {
                space = i;
            }
            if (w >= max) { // wrap line
                int pos = (space > -1) ?
                        (space + 1/* include space */) :
                        (w > max) ? i/* rollback wide char */ : i + 1;
                return new Tuple<>(str.substring(start, pos), pos);
            }
        }
        return new Tuple<>(str.substring(start, end), end);
    }

}
